package com.wufish.javalearning.jvm.bytecode;

/**
 * The type Class modifier.
 *
 * @Author wzj
 * @Create time : 2018/07/03 14:18
 * @Description: 修改Class文件
 */
public class ClassModifier {
    /**
     * 常量池的起始偏移量
     **/
    private static final int CONSTANT_POLL_COUNT_INDEX = 8;
    /**
     * CONSTANT_Utf8_info 的tag
     */
    private static final int CONSTANT_Utf8_info = 1;

    /**
     * 常量池中常量所占的长度
     */
    private static final int[] CONSTANT_ITEM_LENGTH = {-1, -1, -1, 5, 5, 9, 9, 3, 3, 5, 5, 5, 5};

    private static final int u1 = 1;
    private static final int u2 = 2;
    private byte[] classByte;

    /**
     * Instantiates a new Class modifier.
     *
     * @param classByte the class byte
     */
    public ClassModifier(byte[] classByte) {
        this.classByte = classByte;
    }

    /**
     * 修改常量池中的内容
     *
     * @param oldStr the old str
     * @param newStr the new str
     * @return byte [ ]
     */
    public byte[] modifyUTF8Constant(String oldStr, String newStr) {
        // 常量池大小
        int cpc = getConstantPollCount();
        // 常量数据偏移
        int offset = CONSTANT_POLL_COUNT_INDEX + u2;
        for (int i = 0; i < cpc; i++) {
            // 读取一个自己的tag
            int tag = ByteUtils.bytes2Int(classByte, offset, u1);
            if (tag == CONSTANT_Utf8_info) {
                int len = ByteUtils.bytes2Int(classByte, offset + u1, u2);
                offset += (u1 + u2);
                String str = ByteUtils.bytes2String(classByte, offset, len);
                if (str.equalsIgnoreCase(oldStr)) {
                    byte[] strBytes = ByteUtils.string2Bytes(newStr);
                    byte[] strLen = ByteUtils.int2Bytes(newStr.length(), u2);
                    classByte = ByteUtils.byteReplace(classByte, offset - u2, u2, strLen);
                    classByte = ByteUtils.byteReplace(classByte, offset, len, strBytes);
                    return classByte;
                } else {
                    offset += len;
                }
            } else {
                offset += CONSTANT_ITEM_LENGTH[tag];
            }
        }
        return classByte;
    }

    /**
     * 获取常量池中常量的数量
     *
     * @return constant poll count
     */
    public int getConstantPollCount() {
        return ByteUtils.bytes2Int(classByte, CONSTANT_POLL_COUNT_INDEX, u2);
    }

}
